﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace OrderAggregator.InputFormats.Excel
{
    /// <summary>
    /// Excel new format
    /// </summary>
    public class ExcelNewFormat : BaseExcelFormat
    {
        /// <summary>
        /// Instance
        /// </summary>
        public static readonly ExcelNewFormat Instance = new ExcelNewFormat();

        /// <summary>
        /// Constructor
        /// </summary>
        private ExcelNewFormat()
            : base()
        {
        }

        /// <summary>
        /// Parse
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="getStream"></param>
        /// <returns></returns>
        public override BaseOrder Parse(string filePath, Func<System.IO.Stream> getStream)
        {
            var fileExt = System.IO.Path.GetExtension(filePath);

            if (!string.Equals(fileExt, dotXLS, StringComparison.InvariantCultureIgnoreCase) &&
               !string.Equals(fileExt, dotXLSX, StringComparison.InvariantCultureIgnoreCase))
            {
                return null;
            }

            if (string.Equals(fileExt, dotXLS, StringComparison.InvariantCultureIgnoreCase))
            {
                var table = ReadAsDataTable(Path.GetFullPath(filePath));

               
                Func<int, Func<int, object>> getRow =
                    (row) =>
                    {
                        if (row >= table.Rows.Count)
                        {
                            return null;
                        }

                        return (col) => table.Rows[row][col];
                    };

                return Parse(getRow);
            }
            else
            {
                Func<int, Func<int, object>> getRow;
                using (var context = ReadXLSXAsDataTable(Path.GetFullPath(filePath), out getRow))
                {
                    return Parse(getRow);
                };
            }
        }

        private BaseOrder Parse(Func<int, Func<int, object>> getRow)
        {
            int rowIndex;
            var order = TryParseHeader(getRow, out rowIndex);
            
            if (order == null)
            {
                return null;
            }

            int nameColumnId = 0;
            int columnCountId = 0;
            int unitNameId = 0;

            var row = getRow(rowIndex);
            while (row != null)
            {
                var str = row(0) as string;
                if (str == "Код")
                {
                    //строка шапки таблицы позиций


                    columnCountId = FindColumn(1, row, "Шт(Кг)", "Заказ Шт(Кг)");
                    nameColumnId = FindColumn(1, row, "Наименование");
                    unitNameId = FindColumn(1, row, @"Шт\Вес");

                    if (columnCountId < 0 || nameColumnId < 0 || unitNameId < 0)
                    {
                        return null;
                    }


                    rowIndex++;
                    row = getRow(rowIndex);
                    break;
                }

                rowIndex++;
                row = getRow(rowIndex);
            }

            while (row != null)
            {
                var productCode = Convert.ToString(row(0));

                if (string.IsNullOrEmpty(productCode))
                {
                    break;
                }

                var orderRow = new BaseOrderRow();
                orderRow.ProductCode = productCode;
                orderRow.ProductName = row(nameColumnId) as string;
                orderRow.UnitName = row(unitNameId) as string;
                orderRow.Count = Convert.ToDecimal(row(columnCountId));
                
                order.OrderRows.Add(orderRow);

                rowIndex++;
                row = getRow(rowIndex);
            }

            
            

            return order;
        }

        private BaseOrder TryParseHeader(Func<int, Func<int, object>> getRow, out int endRowIndex)
        {
            BaseOrder order = null;

            endRowIndex = 0;
            var row = getRow(endRowIndex);

            while (row != null)
            {
                var cell0 = row(0) as string;

                if (cell0 == "Заявка")
                {
                    order = new BaseOrder();
                    break;
                }

                endRowIndex++;
                row = getRow(endRowIndex);
            }

            if (order == null)
            {
                return null;
            }

            //№ 13926 от 10/07/2013			
            {
                string str = GetNotEmptyCell(row, 1);
               
                if (string.IsNullOrEmpty(str))
                {
                    return null;
                }

                int pos = str.IndexOf(" от ");
                if (pos < 0)
                {
                    return null;
                }

                var strDate = str.Substring(pos + 4).Trim();
                order.ReceiveTime = DateTime.Parse(strDate, RuCulture);

                var strNum = str.Substring(1, pos);
                order.Id = strNum;
            }


            bool findClient = false;
            
            endRowIndex++;
            row = getRow(endRowIndex);

            while (row != null)
            {
                var cell0 = row(0) as string;

                if (cell0 == "От" || cell0 == "От кого")
                {
                    order.Client = GetNotEmptyCell(row, 1);
                    findClient = true;
                    break;
                }

                endRowIndex++;
                row = getRow(endRowIndex);
            }

            if (!findClient)
            {
                return null;
            }

            endRowIndex++;
            return order;
        }

        private static string GetNotEmptyCell(Func<int, object> row, int startColumn)
        {
            //ищем непустую колонку
            for (int i = 0; i < 5; i++)
            {
                var str = row(i + startColumn) as string;

                if (!string.IsNullOrEmpty(str))
                {
                    return str;
                }
            }

            return null;
        }

        private static int FindColumn(int startColumn, Func<int, object> row, params string[] patterns)
        {
            for (int i = 0; i < 10; i++)
            {
                var str = row(i + startColumn) as string;

                if (!string.IsNullOrEmpty(str))
                {
                    str = str.Trim();
                }

                foreach (var pattern in patterns)
                {
                    if (string.Equals(str, pattern, StringComparison.InvariantCultureIgnoreCase))
                    {
                        return i + startColumn;
                    }
                }
            }

            return -1;
        }
    }
}
